/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================================================================
 *
 * author: apache@xuefeng.org
 *
 */

#include "ap_config.h"
#include "ap_mmn.h"
#include "httpd.h"
#include "http_config.h"
#include "http_connection.h"

#include "apr_shm.h"
#include "apr_errno.h"
#include "apr_general.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_time.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif

#if APR_HAS_SHARED_MEMORY
/* ------------------------------------------------------ */

/* share memory start +++++++++++++++++++++++++++++++++++ */
typedef struct stat_queue {
	key_t key;
	unsigned int acc;
} stat_queue;

stat_queue *squeue;

#define DEF_WRITE_LOG_CYCLE			10000
#define DEF_STAT_QUEUE_MAX_SIZE		1000
#define DEF_SHM_SHARED_SIZE			(apr_size_t)(DEF_STAT_QUEUE_MAX_SIZE * sizeof(stat_queue))
#define DEF_SHM_SHARED_FILENAME		"/tmp/apr.staturl"

#define CLEANUP_RETURN(pool, ret) do {	\
	if (NULL != pool) {					\
		apr_pool_destroy(pool);			\
	}									\
	return ret;							\
} while (0)


static int staturl_run(request_rec *r) {

    apr_pool_t		*pool;
	apr_shm_t		*shm;
	key_t			ftok_key;
	int				i, found;

	found = 0;

	if ((key_t)-1 == (ftok_key = ftok(r->filename))) {
		return 0;
	}

	apr_initialize();
    if (APR_SUCCESS != apr_pool_create(&pool, NULL)) {
		CLEANUP_RETURN(pool, -1);
    }

	if (APR_SUCCESS != apr_shm_attach(&shm, DEF_SHM_SHARED_FILENAME, pool)) {
		if (APR_SUCCESS != apr_shm_create(&shm, DEF_SHM_SHARED_SIZE, DEF_SHM_SHARED_FILENAME, pool)) {
			CLEANUP_RETURN(pool, -2);
		}
		if (DEF_SHM_SHARED_SIZE != apr_shm_size_get(shm)) {
			CLEANUP_RETURN(pool, -3);
		}
	}

	if (NULL == (squeue = apr_shm_baseaddr_get(shm))) {
		CLEANUP_RETURN(pool, -4);
	}

	for (i = 0; i < DEF_STAT_QUEUE_MAX_SIZE; i++) {
		if (i && !squeue[i].key) { break; }

		ap_rprintf(r, "node = %d, key = 0x%x, acc = %d\n", i, squeue[i].key, squeue[i].acc);
		if (squeue[i].key == ftok_key) {
			squeue[i].acc++; found = 1;
			break;
		}
	}

	squeue[0].acc++;

	if (!found && (i < DEF_STAT_QUEUE_MAX_SIZE)) {
		squeue[0].key++;
		squeue[i].key = ftok_key;
		squeue[i].acc++;
	}

	if (DEF_WRITE_LOG_CYCLE == squeue[0].acc) {
		// save log file and reset stat queue

		// reset stat queue
		for (i = 0; i < DEF_STAT_QUEUE_MAX_SIZE; i++) {
			squeue[i].key = (key_t)0;
			squeue[i].acc = 0;
		}
	}

	apr_shm_detach(shm);

	return 1;
}

/* apache module start ++++++++++++++++++++++++++++++++++ */
module AP_MODULE_DECLARE_DATA staturl_module;

static int staturl_method_handler (request_rec *r)
{
	if (strcmp("staturl", r->handler)) { return DECLINED; }

	staturl_run(r);

	return DECLINED;
}

static void staturl_register_hooks(apr_pool_t *p)
{
	ap_hook_handler(staturl_method_handler, NULL, NULL, APR_HOOK_LAST);
}

module AP_MODULE_DECLARE_DATA staturl_module = {
    STANDARD20_MODULE_STUFF,
    NULL,					/* create per-directory config structure */
    NULL,					/* merge per-directory config structures */
    NULL,					/* create per-server config structure */
    NULL,					/* merge per-server config structures */
    NULL,					/* command apr_table_t */
    staturl_register_hooks	/* register hooks */
};

/* ------------------------------------------------------ */
#endif
